/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hxg.portmgr.core.dao.impl.jaxb;

import hxg.portmgr.core.dao.DeviceDAO;
import hxg.portmgr.core.device.Device;
import hxg.portmgr.core.device.DeviceModel;
import hxg.portmgr.core.device.DeviceType;
import hxg.portmgr.core.ip.IpAddress;
import hxg.portmgr.core.ip.IpAddressEntry;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import util.Sequence;

/**
 *
 * @author hxg
 */
public final class DeviceDAOJaxbImpl implements DeviceDAO {

    private static final Logger logger = Logger.getLogger(DeviceDAOJaxbImpl.class.getName());
    final private static Map<String, Device> DevicesMap = new ConcurrentHashMap();
    final static File savefile = new File(".\\data\\Device.xml");
    private static final Sequence seq = new Sequence();

    public DeviceDAOJaxbImpl() {
        //load();
        if (!savefile.exists()) {
            savefile.getParentFile().mkdirs();
            save();
        }
    }

    @Override
    public void load() {
        Collection<Device> devs = JaxbDecode(savefile);
        for (Device dev : devs) {
            addDevice(dev);
        }
    }

    @Override
    public void save() {
        JaxbEncode(savefile);
    }

    private void JaxbEncode(File f) {
        //PrintWriter pw = null;
        OutputStream os = null;
        try {
            for (Device dev : getDevices()) {
                if (dev.getId() == 0) {
                    dev.setId(seq.getSeq());
                }
            }
            //pw = new PrintWriter(f);
            os = new FileOutputStream(f);
            JAXBContext jc = JAXBContext.newInstance(DeviceListBean.class);
            Marshaller m = jc.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            DeviceListBean dlist = new DeviceListBean();
            dlist.list.addAll(getDevices());
            //dlist.lastSequence = DeviceSequence.getCurrentValue();
            m.marshal(dlist, os);
        } catch (Exception ex) {
            logger.log(Level.SEVERE, null, ex);
        } finally {
            try {
                os.close();
            } catch (IOException ex) {
                logger.log(Level.SEVERE, null, ex);
            }
        }
    }

    private List<Device> JaxbDecode(File f) {
        try {
            JAXBContext jc = JAXBContext.newInstance(DeviceListBean.class);
            Unmarshaller u = jc.createUnmarshaller();
            DeviceListBean dlist = (DeviceListBean) u.unmarshal(f);
            //DeviceSequence.setCurrentValue(dlist.lastSequence);
            return dlist.list;
        } catch (JAXBException ex) {
            logger.log(Level.SEVERE, null, ex);
            return new ArrayList();
        }
    }

    @Override
    public void addDevice(Device dev) {

        if (dev.getId() == 0) {
            dev.setId(seq.getSeq());
        }
        DevicesMap.put(dev.getIp(), dev);
        for (IpAddressEntry ip : dev.getIps()) {
            if (!IpAddress.isSiteLocalAddress(ip.getIp())) {
                DevicesMap.put(ip.getIp(), dev);
            }
        }
    }

    @Override
    public void addDevices(Collection<Device> devs) {
        for (Device dev : devs) {
            addDevice(dev);
            logger.log(Level.INFO, "添加了设备{0},IP[{1}}]", new Object[]{dev, dev.getIp()});
        }
    }

    @Override
    public List<Device> getDevices() {
        List<Device> devicelists = new ArrayList<>();
        TreeSet<Device> set = new TreeSet();
        set.addAll(DevicesMap.values());
        devicelists.addAll(set);
        return devicelists;
    }

    @Override
    public List<Device> getDevices(DeviceType type) {
        List<Device> list = new ArrayList<>();
        for (Device dev : getDevices()) {
            if (dev.getType().equals(type)) {
                list.add(dev);
            }
        }
        return list;
    }

    @Override
    public Device getDeviceByIp(String ip) {
        if (DevicesMap.containsKey(ip)) {
            return DevicesMap.get(ip);
        } else {
            //第一次循环扫描设备表,找非私网副IP的Device返回
            for (Device dev : getDevices()) {
                for (IpAddressEntry ipe : dev.getIps()) {
                    String devip = ipe.getIp();
                    if (!IpAddress.isSiteLocalAddress(ip)) {
                        if (devip.equals(ip)) {
                            return dev;
                        }
                    }
                }
            }
            //如果还没有,第二次循环扫描设备表,找副IP的Device返回
            for (Device dev : getDevices()) {
                for (IpAddressEntry ipe : dev.getIps()) {
                    String devip = ipe.getIp();
                    if (devip.equals(ip)) {
                        return dev;
                    }
                }
            }
        }
        return new Device();
    }

    @Override
    public void removeDevice(Device dev) {
        for (IpAddressEntry ip : dev.getIps()) {
            DevicesMap.remove(ip.getIp());
            logger.log(Level.INFO, "删除了设备{0},IP[{1}}]", new Object[]{dev, ip.getIp()});
        }
    }

    @Override
    public Device getDeviceById(long devId) {
        if (devId > 0) {
            for (Device dev : DevicesMap.values()) {
                if (dev.getId() == devId) {
                    return dev;
                }
            }
        }
        return new Device();
    }

    @Override
    public List<Device> getDevices(DeviceModel model) {
        List<Device> list = new ArrayList<>();
        for (Device dev : getDevices()) {
            if (dev.getModel().getSysOid().equals(model.getSysOid())) {
                list.add(dev);
            }
        }
        return list;
    }
}
